package cn.gcjxsc.service.account;

import cn.gcjxsc.common.util.validator.BindResult;
import cn.gcjxsc.consts.IntegralRecordType;
import cn.gcjxsc.consts.WithdrawStatus;
import cn.gcjxsc.consts.WithdrawType;
import cn.gcjxsc.data.query.common.WithdrawQuery;
import cn.gcjxsc.data.vo.WithdrawVo;
import cn.gcjxsc.entity.account.Withdraw;
import cn.gcjxsc.entity.salesman.BankCard;
import cn.gcjxsc.entity.salesman.IntegralRecord;
import cn.gcjxsc.entity.salesman.Salesman;
import cn.gcjxsc.entity.salesman.SalesmanAccount;
import cn.gcjxsc.repository.account.WithdrawRepository;
import cn.gcjxsc.repository.specs.WithdrawSpec;
import cn.gcjxsc.service.integral.IntegralRecordService;
import cn.gcjxsc.service.integral.SalesmanAccountService;
import cn.gcjxsc.service.integral.SalesmanService;
import com.zgxl.common.util.DateTimeUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * 提现业务类.
 *
 * @author pumbaa
 * @since 1.0
 */
@Service
public class WithdrawService {
    @Autowired
    private WithdrawRepository withdrawRepository;
    @Autowired
    private SalesmanAccountService accountService;
    @Autowired
    private IntegralRecordService integralRecordService;
    @Autowired
    private SalesmanService salesmanService;

    /**
     * 根据流水号查询提现信息
     *
     * @param sn 提现流水号
     * @return
     */
    public Withdraw findBySn(String sn) {
        return withdrawRepository.findBySn(sn);
    }

    /**
     * 根据id查询提现流水号
     *
     * @param id id
     * @return
     */
    public Withdraw findById(Integer id) {
        return withdrawRepository.findOne(id);
    }


    /**
     * 生成提现流水号
     *
     * @return
     */
    private String generateWithdrawSn() {
        // w+年月日时分秒+毫秒+10位随机数
        // w20171008041122 072 982345
        String datePath = DateTimeUtil.generateSn();
        StringBuilder random = new StringBuilder(System.currentTimeMillis() % 1000 + "");
        for (int i = 0; i < 10; i++) {
            random.append(1 + (int) (Math.random() * 10)).append("");
        }
        return "w" + datePath + random;
    }

    /**
     * 业务员申请提现
     *
     * @param salesman   业务员信息
     * @param amount     提现金额
     * @param bankCard   银行卡号
     * @param bindResult 操作结果
     * @return
     */
    @Transactional
    public Withdraw salesmanApply(Salesman salesman, BigDecimal amount, BankCard bankCard,
                                  BindResult bindResult) {
        SalesmanAccount account = accountService.findBySalesman(salesman);
        if (null == account) {
            bindResult.setErrorMsg("没有可提现的余额");
            return null;
        }
        if (account.getBalance().compareTo(amount) < 0) {
            bindResult.setErrorMsg("余额不足");
            return null;
        }
        //余额
        BigDecimal balance = account.getBalance().subtract(amount);
        String sn = generateWithdrawSn();

        Withdraw withdraw = new Withdraw();
        withdraw.setActAmount(amount);
        withdraw.setAmount(amount);
        withdraw.setBankName(bankCard.getBankName());
        withdraw.setBankBranchName(bankCard.getBankBranchName());
        withdraw.setBankCardNo(bankCard.getBankCardNo());
        withdraw.setCardHolder(bankCard.getCardHolder());
        withdraw.setCheckAuditor("");
        withdraw.setDoneAuditor("");
        withdraw.setCheckTime(0L);
        withdraw.setDoneTime(0L);
        withdraw.setCreated(System.currentTimeMillis() / 1000);
        withdraw.setWithdrawType(WithdrawType.SALESMAN);
        withdraw.setWithdrawStatus(WithdrawStatus.WAIT);
        withdraw.setFeeRate(BigDecimal.ZERO);
        withdraw.setTaxAmount(BigDecimal.ZERO);
        withdraw.setLegal(salesman.getName());
        withdraw.setOwnerId(salesman.getMemberId());
        withdraw.setExtraId(salesman.getId());
        withdraw.setRemark("");
        withdraw.setSn(sn);
        withdraw.setStoreId(salesman.getStoreId());
        withdraw.setSummary("业务员申请提现");

        IntegralRecord record = new IntegralRecord();
        record.setMemberId(salesman.getMemberId());
        record.setSource(salesman.getMemberId().toString());
        record.setStoreId(salesman.getStoreId());
        record.setRate(BigDecimal.ONE);
        record.setSourceAmount(BigDecimal.ZERO);
        record.setRemark("申请提现");
        record.setSn(withdraw.getSn());
        record.setCreated(withdraw.getCreated());
        record.setAmount(withdraw.getAmount().multiply(BigDecimal.valueOf(-1)));
        record.setSalesman(salesman);
        record.setType(IntegralRecordType.WITHDRAW);

        account.setBalance(balance);
        account.setFreezeAmount(account.getFreezeAmount().add(amount));

        withdrawRepository.save(withdraw);
        accountService.saveAccount(account);
        integralRecordService.saveRecord(record);

        return withdraw;
    }

    /**
     * 业务员取消提现
     *
     * @param withdraw 提现记录
     */
    @Transactional
    public void cancelSalesmanWithdraw(Withdraw withdraw) {
        Salesman salesman = salesmanService.findById(withdraw.getExtraId());
        if (null == salesman) {
            throw new RuntimeException("业务员信息不存在");
        }
        withdraw.setCheckTime(System.currentTimeMillis() / 1000);
        withdraw.setWithdrawStatus(WithdrawStatus.CANCELED);
        withdraw.setCheckAuditor(salesman.getName());
        withdraw.setRemark("主动取消提现申请");
        doInvalidSalesmanWithdraw(withdraw, salesman, "业务员主动取消提现申请");
        withdrawRepository.save(withdraw);
    }

    /**
     * 拒绝业务提现申请
     *
     * @param withdraw 提现记录
     * @param auditor  审核人
     * @param reason   原因
     */
    @Transactional
    public void rejectSalesmanWithdraw(Withdraw withdraw, String auditor, String reason) {
        Salesman salesman = salesmanService.findById(withdraw.getExtraId());
        if (null == salesman) {
            throw new RuntimeException("业务员信息不存在");
        }

        withdraw.setCheckTime(System.currentTimeMillis() / 1000);
        withdraw.setCheckAuditor(auditor);
        withdraw.setRemark(reason);
        withdraw.setWithdrawStatus(WithdrawStatus.REJECTED);

        doInvalidSalesmanWithdraw(withdraw, salesman, reason);
        withdrawRepository.save(withdraw);
    }

    /**
     * 拒绝/取消业务员提现
     *
     * @param withdraw 提现数据
     * @param salesman 业务员
     * @param remark   备注信息
     */
    private void doInvalidSalesmanWithdraw(Withdraw withdraw, Salesman salesman, String remark) {
        SalesmanAccount account = accountService.findBySalesman(salesman);

        IntegralRecord record = new IntegralRecord();
        record.setMemberId(salesman.getMemberId());
        record.setSource(salesman.getMemberId().toString());
        record.setStoreId(salesman.getStoreId());
        record.setRate(BigDecimal.ONE);
        record.setSourceAmount(withdraw.getAmount());
        record.setRemark(remark);
        record.setSn(withdraw.getSn());
        record.setCreated(withdraw.getCheckTime());
        record.setAmount(withdraw.getAmount());
        record.setSalesman(salesman);
        record.setType(IntegralRecordType.WITHDRAW);

        account.setFreezeAmount(account.getFreezeAmount().subtract(withdraw.getAmount()));
        account.setBalance(account.getBalance().add(withdraw.getAmount()));

        accountService.saveAccount(account);
        integralRecordService.saveRecord(record);
    }

    /**
     * 通过审核
     *
     * @param withdraw 提现记录
     * @param auditor  操作人员
     */
    @Transactional
    public Withdraw passWithdraw(Withdraw withdraw, String auditor) {
        withdraw.setCheckTime(System.currentTimeMillis() / 1000);
        withdraw.setCheckAuditor(auditor);
        withdraw.setWithdrawStatus(WithdrawStatus.PASSED);
        return withdrawRepository.save(withdraw);
    }

    /**
     * 提现处理完成
     *
     * @param withdraw 提现记录
     * @param auditor  操作人员
     */
    @Transactional
    public void doneWithdraw(Withdraw withdraw, String auditor) {
        withdraw.setDoneTime(System.currentTimeMillis() / 1000);
        withdraw.setDoneAuditor(auditor);
        withdraw.setWithdrawStatus(WithdrawStatus.DONE);

        withdrawRepository.save(withdraw);
    }

    /**
     * 查询提现列表
     *
     * @param filter   过滤条件
     * @param page     当前页
     * @param pageSize 每页记录数
     * @return
     */
    public Page<Withdraw> findAll(WithdrawQuery filter, int page, int pageSize) {
        Sort sort;
        if (filter.getDateType() == WithdrawQuery.DATE_TYPE_CHECK) {
            sort = new Sort(Sort.Direction.DESC, "checkTime");
        } else if (filter.getDateType() == WithdrawQuery.DATE_TYPE_DONE) {
            sort = new Sort(Sort.Direction.DESC, "doneTime");
        } else {
            sort = new Sort(Sort.Direction.DESC, "created");
        }
        PageRequest pageRequest = new PageRequest(page - 1, pageSize, sort);
        return withdrawRepository.findAll(WithdrawSpec.buildSpec(filter), pageRequest);
    }

    public WithdrawVo convertWithdraw(Withdraw withdraw) {
        WithdrawVo vo = new WithdrawVo();
        BeanUtils.copyProperties(withdraw, vo);
        vo.setWithdrawStatus(withdraw.getWithdrawStatus().getStatus());
        vo.setWithdrawType(withdraw.getWithdrawType().ordinal());
        return vo;
    }
}
